﻿using System;
using System.IO;
using System.Security.Cryptography;
using System.Threading;



namespace CSharp.Libs.Media
{
    #region event handlers
    public delegate void FileHashCalculatedEventHandler(object sender, FileHashCalculatedEventArgs e);
    public class FileHashCalculatedEventArgs
    {
        public bool HashCalculationSuccessfull { get; set; }
        public string CalculatedHash { get; set; }
    }
    #endregion



    public class FileHashCalculator : IDisposable
    {
        #region declarations
        #region event handling
        public event FileHashCalculatedEventHandler FileHashCalculated;
        protected void OnFileHashCalculated(
            FileHashCalculatedEventArgs ea)
        {
            if (FileHashCalculated != null)
            {
                FileHashCalculated(this, ea);
            }
        }
        #endregion
        #endregion



        #region constructor
        public FileHashCalculator()
        {

        }

        #region dispose pattern (http://www.codeproject.com/Articles/15360/Implementing-IDisposable-and-the-Dispose-Pattern-P)
        // some fields that require cleanup
        private bool disposed = false; // to detect redundant calls

        protected virtual void Dispose(bool disposing)
        {
            if (!disposed)
            {
                if (disposing)
                {
                    // clean up managed handles
                    FileHashCalculated = null;
                }

                disposed = true;
            }
        }

        public void Dispose()
        {
            Dispose(true);
        }
        #endregion
        #endregion



        #region properties
        public string CalculatedHash { get; set; }
        public string FullFileName { get; set; }
        #endregion



        #region methods
        public void CalculateFileHash()
        {
            try
            {
                if (!File.Exists(FullFileName))
                {
                    throw new ArgumentException("FileName", "File not found");
                }

                using (var stream = new BufferedStream(File.OpenRead(FullFileName), 1200000))
                {
                    SHA256Managed sha = new SHA256Managed();
                    byte[] checksum = sha.ComputeHash(stream);
                    CalculatedHash = BitConverter.ToString(checksum).Replace("-", String.Empty);
                    OnFileHashCalculated(new FileHashCalculatedEventArgs()
                    {
                        CalculatedHash = CalculatedHash,
                        HashCalculationSuccessfull = true
                    });
                }
            }
            catch (Exception ex)
            {
                OnFileHashCalculated(new FileHashCalculatedEventArgs() { CalculatedHash = "", HashCalculationSuccessfull = false });
                throw ex;
            }
        }

        public void CalculateFileHashAsync()
        {
            Thread thrCalculateHash = new Thread(CalculateFileHash);
            thrCalculateHash.Start();
        }
        #endregion
    }
}
